/*
 *  Copyright (C) 1993  Robert Davis
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of Version 2, or any later version, of 
 *  the GNU General Public License as published by the Free Software 
 *  Foundation.
 */

static char RCSId[]="$Id: GnuplotInspector.m,v 1.5 1993/05/30 20:09:53 davis Exp $";


#import <appkit/Application.h>
#import <appkit/Text.h>
#import <appkit/TextField.h>
#import <ctype.h>			/* isspace()	*/
#import <libc.h>			/* MAXPATHLEN	*/
#import <objc/NXBundle.h>
#import <objc/objc.h>

#import "GnuplotInspector.h"

#define TYPE_UNKNOWN	1		/* plot types	*/
#define TYPE_TWOD	2
#define TYPE_CONTOURS	4
#define TYPE_POLAR	8
#define TYPE_PARAMETRIC	16


@interface GnuplotInspector (Private)
- _getCommandsFromBuffer:(const char *)buf end:(const char *const)end;
@end


static const char *skipSpace (const char *cur, const char *const end)
{
    while (cur && (cur != end) && *cur && isspace (*cur))
	cur++;
    return cur;
}


static const char *skipToSpace (const char *cur, const char *const end)
{
    while (cur && (cur != end) && *cur && !isspace (*cur))
	cur++;
    return cur;
}


static int almost (const char *cur, const char *target, const char *const end)
{
    if (cur && target) {

	int i;
	const char *c;
	BOOL past = NO;

	i = 0;
	for (c = cur; (c != end) && *c && !isspace (*c); c++)
	    i++;

	for (; i ; i--) {
	    if (*cur == *target) {
		cur++;
		target++;
	    } else {
		if (*target == '$') {
		    past = YES;
		    i++;
		    target++;
		} else
		    return NO;
	    }
	}

	return (past || (*target == '$') || (*target == '\0'));

    }

    return NO;
}


static const char *getQuotedString (char *quoted, const char *from,
				    const char *const end)
{
    if (from && (from != end)) {

	while ((from != end) && isspace(*from) && (*from != '\n'))
	    from++;

	if ((from != end) && ((*from == '\'') || (*from == '"'))) {

	    char *cur;
	    char c = *(from++);

	    cur = quoted;
	    while ((from != end) && *from && (*from != c) && (*from != '\n'))
		*(cur++) = *(from++);
	    *cur = '\0';
	}

    }

    return from;
}


@implementation GnuplotInspector

static id gnuplotInspector = nil;

+ new
{
    if (gnuplotInspector == nil) {
        char		path[MAXPATHLEN+1];
        NXBundle	*bundle = [NXBundle bundleForClass:self];
      
        self = gnuplotInspector = [super new];
        if ([bundle getPath:path 
                forResource:"GnuplotInspector"
                ofType:"nib"]) {

            [NXApp loadNibFile:path owner:gnuplotInspector];
        } else {
            fprintf (stderr, "Couldn't load GnuplotInspector.nib\n");
            gnuplotInspector = nil;
        }
    }

    return gnuplotInspector;
}



- ok:sender
{
    [super ok:sender];
    return self;
}


- revert:sender
{
    NXStream	*s;
    char	*text;
    char	path[MAXPATHLEN];
    int		len, maxlen;

    /*  Open a memory stream and get a pointer to the buffer */

    [self selectionPathsInto:path separator:':'];
    if (s = NXMapFile (path, NX_READONLY)) {

	NXGetMemoryBuffer(s, &text, &len, &maxlen);

	[self _getCommandsFromBuffer:text end:text+len];
	NXCloseMemory (s,NX_FREEBUFFER);

	if (type & TYPE_UNKNOWN)
	    strcpy (typestring, "Unknown");
	else {
	    if (type & TYPE_TWOD) {
		strcpy (typestring, "Two-dimensional");
		if (type & TYPE_POLAR)
		    strcat (typestring, " Polar");
	    } else {
		strcpy (typestring, "Three-dimensional");
		if (type & TYPE_CONTOURS)
		    strcat (typestring, " with Contours");
	    }

	    if (type & TYPE_PARAMETRIC)
		strcat (typestring, " Parametric");
	}

	[typeField setStringValue:typestring];
	[titleText setText:title];
	[expressionsText setText:expressions];

    }

    [super revert:sender];
    return self;
}


@end



@implementation GnuplotInspector(Private)

- _getCommandsFromBuffer:(const char *)buf end:(const char *const) end
{
    const char	*cur;
    char	*tc = title;
    char	*ec = expressions;

    type = TYPE_UNKNOWN;
    *title = '\0';
    *expressions = '\0';

    cur = skipSpace (buf, end);
    while (cur && (cur != end) && *cur) {

	if (almost (cur, "se$t", end)) {		/* set...	*/
	    cur = skipSpace(skipToSpace (cur, end), end);

	    if (almost (cur, "tit$le", end)) {		/* ...title */
		cur = skipToSpace (cur, end);
		cur = getQuotedString (tc, cur, end);

	    } else if (almost (cur, "noco$ntour", end))
		type &= ~TYPE_CONTOURS;

	    else if (almost (cur, "co$ntour", end))
		type |= TYPE_CONTOURS;
		
	    else if (almost (cur, "nopo$lar", end))
		type &= ~TYPE_POLAR;

	    else if (almost (cur, "pol$ar", end))
		type |= TYPE_POLAR;

	    else if (almost (cur, "nopar$ametric", end))
		type &= ~TYPE_PARAMETRIC;

	    else if (almost (cur, "par$ametric", end))
		type |= TYPE_PARAMETRIC;

	} else if (almost(cur,"p$lot",end) || almost(cur,"sp$lot",end)) {
	    type &= ~TYPE_UNKNOWN;
	    if (*cur == 'p')
		type |= TYPE_TWOD;
	    else
		type &= ~TYPE_TWOD;

	    cur = skipSpace(skipToSpace (cur, end), end);
	    while (cur != end) {
		if ((*cur == '\'') || (*cur == '"')) {
		    char	 c = *(ec++) = *(cur++);
		    while ((cur != end) && (*cur != c) && (*cur != '\n'))
			*(ec++) = *(cur++);
		    if (*cur == c)
			*(ec++) = *(cur++);

		} else if (*cur == '(') {
		    int		count = 1;
		    while (count) {
			*(ec++) = *(cur++);
			if (cur != end) {
			    if (*cur == '(')
				count++;
			    else if (*cur == ')')
				count--;
			} else
			    break;
		    }
		    if (cur != end)
			*(ec++) = *(cur++);
		    else
			break;

		} else if (*cur == '\n') {
		    if (*(cur-1) == '\\') {
			ec--;
			cur = skipSpace(cur, end);
		    } else
			break;

		} else if (*cur == ',') {
		    *(ec++) = '\n';
		    cur = skipSpace(cur+1, end);

		} else if (*cur == '#')
		    break;

		else
		    *(ec++) = *(cur++);
	    }
	    *ec = '\0';

	    break;	/* Ignore eveything after the first plot command */
	}

	while ((cur != end) && (*cur != '\n'))		/* Go to next line */
	    cur++;
	cur = skipSpace (cur, end);
    }

    return self;
}


// Shuts up the compiler about unused RCSId
- (const char *) rcsid
{
    return RCSId;
}

@end
